home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-wos-src
/
vlink
/
support.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
11KB
|
492 lines
/* $VER: vlink support.c V0.5e (05.10.98)
*
* This file is part of vlink, a portable linker for multiple
* object formats.
* Copyright (c) 1997-99 Frank Wille
*
* vlink is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
* vlink may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.5e (05.10.98) phx
* insertnode() is now insertbehind(). New functions insertbefore()
* and addhead().
* v0.5d (22.08.98) phx
* Faster allocation routines using large memory chunks. They must
* be activated by #define FASTALLOC.
* v0.3 (12.04.98) phx
* Replaced l2bh(),l2bw(),read16(),read32(),write16(),write32()
* by swap16(),swap32(),read16sw(),read32sw(),write16sw(),write32sw().
* fwrite32() is now called fwrite32be().
* v0.2 (07.03.98) phx
* insertnode().
* v0.1 (27.02.98) phx
* First version that seems to link AmigaOS ADOS and EHF
* objects and libraries. Many common features, like linking
* sections together which have relative references, are
* still missing. Also, PowerPC-ELF32 support is about to come.
* v0.0 (04.08.97) phx
* File created. Project started on a beautiful summer-day
* at the North Sea beach of Cuxhaven. :)
* This file is based on support.c v0.4 of the portable
* PowerPC assembler "pasm".
*/
#define SUPPORT_C
#include "vlink.h"
void *alloc(size_t);
void *alloczero(size_t);
char *allocstring(char *);
void *alloc_hashtable(size_t);
void initlist(struct list *);
void insertbefore(struct node *,struct node *);
void insertbehind(struct node *,struct node *);
void addhead(struct list *,struct node *);
void addtail(struct list *,struct node *);
struct node *remhead(struct list *);
struct node *remnode(struct node *);
char *mapfile(char *);
char *base_name(char *);
char *check_name(char *);
int checkrange(uint32,int,bool);
uint16 swap16(uint16);
uint32 swap32(uint32);
uint16 read16sw(uint8 *);
uint32 read32sw(uint8 *);
void write16sw(uint8 *,uint16);
void write32sw(uint8 *,uint32);
void fwritex(FILE *,void *,size_t);
void fwrite32be(FILE *,uint32);
void fwrite_align(FILE *,uint32,uint32);
unsigned long elf_hash(unsigned char *);
unsigned long align(unsigned long,unsigned long);
int shiftval(uint32);
static size_t filesize(FILE *,char *);
static char *unnamed_txt = "unnamed";
#ifdef FASTALLOC
static struct MemChunk *new_chunk(void);
void init_mem(void);
#define CHUNKSIZE (0x40000-sizeof(void *)-sizeof(void *)-8)
struct MemChunk { /* Large memory chunks for faster allocation */
struct MemChunk *next;
unsigned char *ptr; /* pointer to available memory in this chunk */
uint32 free; /* number of bytes free */
#ifndef ALIGNOFF4
uint32 align; /* only for 64-bit alignment */
#endif
unsigned char mchunk[CHUNKSIZE];
};
static struct MemChunk *mem; /* first memory chunk for alloc() */
static struct MemChunk *new_chunk()
{
struct MemChunk *m;
if (!(m = (struct MemChunk *)malloc(sizeof(struct MemChunk))))
error(1); /* out of memory */
m->next = NULL;
m->ptr = m->mchunk;
m->free = CHUNKSIZE;
return (m);
}
void init_mem()
{
mem = new_chunk();
}
#endif
void *alloc(size_t size)
/* allocate memory and print error message if not enough available */
{
#ifdef FASTALLOC /* faster, but needs more memory */
struct MemChunk *m=mem,*n;
uint32 bytes;
void *p;
if (!(bytes = (uint32)(size+7) & ~7)) /* return 64-bit aligned memory */
bytes = 8;
if (bytes > CHUNKSIZE) {
/* get an own block, for so much memory */
if (!(p = malloc((size_t)bytes)))
error(1); /* out of memory */
return (p);
}
for (;;) {
if (bytes <= m->free) {
p = (void *)m->ptr;
m->free -= bytes;
m->ptr += bytes;
return (p);
}
if (!(n = m->next))
n = m->next = new_chunk();
m = n;
}
#else
void *p;
if (!size)
size = 1;
if (!(p = malloc(size)))
error(1); /* out of memory */
return (p);
#endif
}
void *alloczero(size_t size)
/* same as alloc() but zeroes the allocated memory */
{
void *p = alloc(size);
memset(p,0,size);
return (p);
}
char *allocstring(char *s)
/* allocate space for a single string */
/* @@@ this should be improved by some kind of string buffer */
{
char *p = alloc(strlen(s)+1);
strcpy(p,s);
return (p);
}
void *alloc_hashtable(size_t entries)
{
return (alloczero(entries * sizeof(void *)));
}
void initlist(struct list *l)
/* initializes a list structure */
{
l->first = (struct node *)&l->dummy;
l->dummy = NULL;
l->last = (struct node *)&l->first;
}
void insertbefore(struct node *n,struct node *sn)
/* insert node n directly before node sn */
/* sn must be a real node - no dummy nodes allowed! */
{
struct node *pn = sn->pred;
n->next = sn;
n->pred = pn;
pn->next = sn->pred = n;
}
void insertbehind(struct node *pn,struct node *n)
/* insert node n directly behind node pn */
/* pn must be a real node - no dummy nodes allowed! */
{
struct node *sn = pn->next;
n->next = sn;
n->pred = pn;
pn->next = sn->pred = n;
}
void addhead(struct list *l,struct node *n)
/* add node as first element of list */
{
struct node *fn = l->first;
n->pred = fn->pred;
fn->pred = n;
n->next = fn;
l->first = n;
}
void addtail(struct list *l,struct node *n)
/* add node as last element of list */
{
struct node *ln = l->last;
n->next = ln->next;
ln->next = n;
n->pred = ln;
l->last = n;
}
struct node *remhead(struct list *l)
/* remove first node in list and return a pointer to it */
{
struct node *n = l->first;
if (n->next) {
l->first = n->next;
n->next->pred = n->pred;
return (n);
}
return (NULL);
}
struct node *remnode(struct node *n)
/* remove a node from a list */
{
n->next->pred = n->pred;
n->pred->next = n->next;
return (n);
}
char *mapfile(char *name)
/* map a complete file into memory and return its address */
/* the file's length is returned in *(p-sizeof(size_t)) */
{
FILE *fp;
char *p=NULL;
size_t fsiz;
if (fp = fopen(name,"r")) {
fsiz = filesize(fp,name);
p = alloc(fsiz+sizeof(size_t));
*(size_t *)p = fsiz; /* store file size before the text starts */
p += sizeof(size_t);
if (fread(p,1,fsiz,fp) != fsiz) {
fclose(fp);
error(7,name); /* read error */
}
fclose(fp);
}
return (p);
}
static size_t filesize(FILE *fp,char *name)
{
/* somebody knows a better way to determine file size in ANSI C? */
long oldpos,size;
if ((oldpos = ftell(fp)) >= 0)
if (fseek(fp,0,SEEK_END) >= 0)
if ((size = ftell(fp)) >= 0)
if (fseek(fp,oldpos,SEEK_SET) >= 0)
return ((size_t)size);
fclose(fp);
error(5,name); /* read error - doesn't return */
}
char *base_name(char *s)
/* returns last part of a path - the file name itself */
{
char c;
int l = strlen(s);
while (l--) {
c = s[l];
if (c== '/' || c==':')
return (&s[l+1]);
}
return (s);
}
char *check_name(char *name)
/* returns "unnamed", if name is a NULL-pointer */
{
if (name)
return (name);
return (unnamed_txt);
}
int checkrange(uint32 val,int size,bool sign)
/* Checks if an integer value is in range, size=3 means 26-bit (B-instr.) */
/* If the check fails, the number of bits is returned (8, 16, 26) */
{
if (sign) {
int32 sval = (int32)val;
switch (size) {
case 1:
if (sval>0x7f || sval<-0x80)
return (8);
break;
case 2:
if (sval>0x7fff || sval<-0x8000)
return (16);
break;
case 3:
if (sval>0x1ffffff || sval<-0x2000000)
return (26);
break;
}
}
else {
switch (size) {
case 1:
if (val>0xff)
return (8);
break;
case 2:
if (val>0xffff)
return (16);
break;
case 3:
if (val>0x3ffffff)
return (26);
break;
}
}
return (0);
}
uint16 swap16(uint16 x)
/* 16-bit endian conversion */
{
return ((x&0xff)<<8 | (x&0xff00)>>8);
}
uint32 swap32(uint32 x)
/* 32-bit endian conversion */
{
return ((x&0xff)<<24 | (x&0xff00)<<8 |
(x&0xff0000)>>8 | (x&0xff000000)>>24);
}
uint16 read16sw(uint8 *p)
/* read 16 bit word with endian conversion */
{
return (((uint16)*p)<<8 | ((uint16)*(p+1)));
}
uint32 read32sw(uint8 *p)
/* read 32 bit word with endian conversion */
{
return (((uint32)*p)<<24 | ((uint32)*(p+1))<<16 |
((uint32)*(p+2))<<8 | ((uint32)*(p+3)));
}
void write16sw(uint8 *p,uint16 x)
/* write 16 bit word with endian conversion */
{
*p++ = (uint8)((x>>8)&0xff);
*p = (uint8)(x&0xff);
}
void write32sw(uint8 *p,uint32 x)
/* write 32 bit word with endian conversion */
{
*p++ = (uint8)((x>>24)&0xff);
*p++ = (uint8)((x>>16)&0xff);
*p++ = (uint8)((x>>8)&0xff);
*p = (uint8)(x&0xff);
}
void fwritex(FILE *fp,void *buf,size_t len)
/* write a buffer of len bytes, with check for len=0 and write error */
{
if (len) {
if (!fwrite(buf,1,len,fp)) {
fclose(fp);
error(31,gvars.dest_name); /* write error */
}
}
}
void fwrite32be(FILE *fp,uint32 w)
/* write a big endian 32 bit word */
{
uint32 be = ECVW(w);
if (!fwrite(&be,1,sizeof(uint32),fp)) {
fclose(fp);
error(31,gvars.dest_name); /* write error */
}
}
void fwrite_align(FILE *fp,uint32 a,uint32 n)
/* writes as many zero bytes as required for alignment a (a bits */
/* must be zero) with current file offset n */
{
static uint8 alignment_bytes[MAX_FWALIGN];
a = 1<<a;
if ((n = (a-(n&(a-1))&(a-1))) > MAX_FWALIGN)
ierror("fwrite_align(): Alignment > %d required",MAX_FWALIGN);
fwritex(fp,alignment_bytes,n);
}
unsigned long elf_hash(unsigned char *name)
/* calculate a hash code as used in ELF objects */
{
unsigned long h=0,g;
while (*name) {
h = (h << 4) + *name++;
if (g = h & 0xf0000000)
h ^= g >> 24;
h &= ~g;
}
return (h);
}
unsigned long align(unsigned long addr,unsigned long alignment)
/* return number of bytes required to achieve alignment */
{
unsigned long a = (1<<alignment) - 1;
return (((addr+a)&~a) - addr);
}
int shiftval(uint32 x)
/* returns number of 0-bits before the first 1-bit - something like */
/* an integer-log2() function - returns 0 on x=0 */
{
int i;
if (x == 0)
return (0);
for (i=0; i<32; i++) {
if (x & 1)
break;
x >>= 1;
}
return (i);
}